package com.ruoyi.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.project.domain.entity.*;
import com.ruoyi.project.domain.query.ProjectCostingQuery;
import com.ruoyi.project.domain.query.ProjectPayQuery;
import com.ruoyi.project.domain.query.ProjectSaleQuery;
import com.ruoyi.project.mapper.ProjectCostingMapper;
import com.ruoyi.project.mapper.ProjectPayMapper;
import com.ruoyi.project.service.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class ProjectCostingServiceImpl extends ServiceImpl<ProjectCostingMapper, ProjectCosting> implements IProjectCostingService {

    @Resource
    private ProjectCostingMapper projectCostingMapper;


    @Resource
    private IProjectGoodsService projectGoodsService;


    @Resource
    private IProjectSaleService projectSaleService;

    @Resource
    private IProjectService projectService;

    @Resource
    private IProjectSaleService saleService;


    @Resource
    private IProjectCostingService projectCostingService;


    //分页
    @Override
    public TableDataInfo getPage(ProjectCostingQuery query) {
        Page<Object> page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<ProjectCosting> list = projectCostingMapper.getList(query);
        return new TableDataInfo(list, page.getTotal());
    }

    //新增
    @Override
    public Boolean addInfo(ProjectCosting project) {
        return this.save(project);
    }

    @Override
    public Boolean updateInfo(ProjectCosting project) {
        project.setOperator(SecurityUtils.getLoginUser().getUser().getNickName());
        //1.修改提交的备注编码实际是 设备名称型号参数的拼接
        //2.实际需要使用提交上来的goodsId查询对应的设备
        if (StringUtils.isEmpty(project.getRemarkCode()) || StringUtils.isEmpty(project.getGoodsId())) {
//            throw new RuntimeException("请选择对应的备注编码重新提交");
            //删除原来的
            project.setGoodsId("");
            project.setStatus("1");
            project.setRemarkCode("");
            return this.updateById(project);
        }
        ProjectGoods goods = projectGoodsService.getInfoById(project.getGoodsId());
        //重新设置一下备注编码
        String modal = goods.getModal();
        project.setRemarkCode(modal);
        //重新设置modal 应该保留清单中原始的型号modal
        if (goods != null) {
            project.setStatus("0");//取消标记
        }
        return this.updateById(project);

    }

    @Override
    public Boolean deleteInfo(String id) {
        return this.removeById(id);
    }

    @Override
    public ProjectCosting getInfoById(String id) {
        return this.getById(id);
    }

    @Override
    public List<ProjectCosting> getList(ProjectCostingQuery query) {
        LambdaQueryWrapper<ProjectCosting> wrapper = new QueryWrapper<ProjectCosting>().lambda();
        wrapper.eq(query.getProjectNo() != null, ProjectCosting::getProjectNo, query.getProjectNo());

        //查询管家婆对应的出库单 有没有能够对应上的？
        return this.list(wrapper);
    }

    @Override
    public TableDataInfo page(ProjectCostingQuery query) {
        Page<Object> page = PageHelper.startPage(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<ProjectCosting> wrapper = new QueryWrapper<ProjectCosting>().lambda();
        wrapper.eq(query.getProjectNo() != null, ProjectCosting::getProjectNo, query.getProjectNo());
        List<ProjectCosting> list = this.list(wrapper);

        for (ProjectCosting projectCosting : list) {
            //折扣率乘以100显示
            if (StringUtils.isNotEmpty(projectCosting.getDiscountRate())) {
                BigDecimal showRate = new BigDecimal(projectCosting.getDiscountRate()).multiply(new BigDecimal(100));
                projectCosting.setDiscountRate(showRate.toString());
            }
        }
        return new TableDataInfo(list, page.getTotal());
    }


    public String importCosting(List<ProjectCosting> list, String projectNo, boolean isDelete, String type) {
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("导入用户数据不能为空！");
        }
        Project projectInfo = projectService.getById(projectNo);
        if (projectInfo == null) {
            throw new ServiceException("项目不存在！");
        }
        if (projectInfo.getHousekeeperProject() == null) {
            throw new ServiceException("请先关联管家婆项目！");
        }
        // 预加载必要数据
        String housekeeperProject = projectInfo.getHousekeeperProject();

        //判断上传的类型 如果是正式清单 就和合同金额比较 如果是竣工结算清单 就和结算金额比较

        BigDecimal contractAmount = projectInfo.getContractAmount();
        BigDecimal settlementAmount = projectInfo.getSettlementAmount();

        if (contractAmount == null) {
            throw new RuntimeException("请先填写合同金额");
        }

        //合同金额和结算金额相等的话 不用重新上传
        if (contractAmount.compareTo(BigDecimal.ZERO) == 0) {
            return "success";
        }

        if ("22".equals(type)) {
            if (projectInfo.getSettlementAmount() == null) {
                throw new RuntimeException("必须先填写结算金额");
            }
            contractAmount = projectInfo.getSettlementAmount();
        }


        // 预处理折扣率并过滤无效数据
        List<ProjectCosting> validList = new ArrayList<>();
        String operator = SecurityUtils.getLoginUser().getUser().getNickName();

        //管家婆出库单
        LambdaQueryWrapper<ProjectSale> saleWrapper = new QueryWrapper<ProjectSale>().lambda();
        saleWrapper.eq(ProjectSale::getHousekeeperProject, housekeeperProject);
        List<ProjectSale> saleList = saleService.list(saleWrapper);

        //收集设备id
        List<String> goodsIds = new ArrayList<>();
        for (ProjectSale projectSale : saleList) {
            String goodsId = projectSale.getGoodsId();
            goodsIds.add(goodsId);
        }
        LambdaQueryWrapper<ProjectCosting> oldWrapper = new QueryWrapper<ProjectCosting>().lambda();
        oldWrapper.eq(ProjectCosting::getProjectNo, projectNo);
        List<ProjectCosting> oldList = this.list(oldWrapper);
        //判断 上传的是结算清单 和正式清单对比
        if ("22".equals(type) && CollectionUtils.isNotEmpty(oldList)) {
            // 步骤1：构建旧列表的映射表（Key为 name|model）
            Map<String, ProjectCosting> oldCostingMap = new HashMap<>();
            for (ProjectCosting oldCosting : oldList) {
                if (oldCosting.getCount() == null || oldCosting.getCount().compareTo(BigDecimal.ZERO) == 0) {
                    // 表示 count 等于 0
                    continue;
                }
                String key = buildKey(oldCosting.getName(), oldCosting.getModel());
                // 仅保留第一个匹配的旧项（可根据需求调整）
                if (!oldCostingMap.containsKey(key)) {
                    oldCostingMap.put(key, oldCosting);
                }
            }
            // 步骤2：遍历新列表，匹配旧列表并合并字段
            for (ProjectCosting newCosting : list) {
                // 过滤无效数量
                if (newCosting.getCount() == null || newCosting.getCount().compareTo(BigDecimal.ZERO) == 0) {
                    // 表示 count 等于 0
                    continue;
                }
                // 生成新项的Key
                String newKey = buildKey(newCosting.getName(), newCosting.getModel());
                // 如果旧列表中存在匹配项，同步字段
                if (oldCostingMap.containsKey(newKey)) {
                    ProjectCosting oldCosting = oldCostingMap.get(newKey);
                    // 同步旧列表的字段到新项
                    newCosting.setStatus(oldCosting.getStatus());
                    newCosting.setRemarkCode(oldCosting.getRemarkCode());
                    newCosting.setGoodsId(oldCosting.getGoodsId());
                } else {
                    ProjectCosting costingErr = oldCostingMap.get(newKey);
                }
                // 公共处理逻辑（折扣率、总价校验等）
                // 设置公共字段
                newCosting.setProjectNo(projectNo);
                newCosting.setOperator(operator);

                // 处理折扣率（提前在Excel导入时处理更佳）
                // 将字符串转换为 double
                BigDecimal rate = StringUtils.isNotEmpty(newCosting.getDiscountRate()) ? new BigDecimal(newCosting.getDiscountRate()) : BigDecimal.ONE;
                try {
                    // 创建 DecimalFormat 实例，保留四位小数，并显示前导零
//                    DecimalFormat df = new DecimalFormat("0.0000"); // 四位小数，且始终显示整数部分
                    DecimalFormat df = new DecimalFormat("0.####");
                    // 格式化
                    String formattedRate = df.format(rate);
                    // 设置回 projectCosting 对象
                    newCosting.setDiscountRate(formattedRate);
                } catch (NumberFormatException e) {
                    newCosting.setDiscountRate("0");
                }

                //数量
                BigDecimal count = newCosting.getCount();

                //单价
                BigDecimal price = newCosting.getPrice();

                //清单中的总价
                BigDecimal totalPrice = newCosting.getTotalPrice();

                if (price == null) {
                    throw new ServiceException("请填写设备“" + newCosting.getName() + "”的单价后重新上传");
                }

                //计算的总价
                BigDecimal calculatedTotal = count.multiply(price);

                BigDecimal diff = calculatedTotal.subtract(totalPrice).abs();
                if (diff.compareTo(BigDecimal.ONE) > 0) { // 如果差值大于 1 元
                    throw new ServiceException("设备“" + newCosting.getName() + "”的数量为:" + count + ",单价为:" + price + " 总价应为:" + calculatedTotal + ",与实际清单中的总价:" + totalPrice + ",不符,差额为:" + diff + ",请正确填写后再上传");
                }

                //如果excel中有折扣率和折扣价 使用计算的总价乘以折扣率 判断是否等于折后价(误差允许在一块钱之内)
                if (StringUtils.isNotEmpty(newCosting.getDiscountRate()) && newCosting.getDiscountPrice() != null) {
                    //计算的折后价 总价乘以折扣率
                    BigDecimal disTotal = calculatedTotal.multiply(rate);
                    // 计算差值的绝对值
                    BigDecimal discountPrice = Optional.ofNullable(newCosting.getDiscountPrice())
                            .orElse(BigDecimal.ONE);
                    BigDecimal diff1 = disTotal.subtract(discountPrice).abs();
                    // 判断是否超过允许的误差范围（1元）
                    if (diff1.compareTo(BigDecimal.ONE) > 0) {
                        throw new ServiceException("设备“" + newCosting.getName() + "”的总价为:" + calculatedTotal + ",折扣率为:" + rate + ",折后价应为:" + disTotal + "与实际清单中的折后总价:" + newCosting.getDiscountPrice() + " 不符,请正确填写后再上传");
                    }
                }
                validList.add(newCosting);
            }
        } else {
            for (ProjectCosting costing : list) {
                if (costing == null) {
                    continue; // 跳过 null 元素
                }
                //过滤掉没有数量的
                if (costing.getCount() == null || costing.getCount().compareTo(BigDecimal.ZERO) == 0) {
                    // 表示 count 等于 0
                    continue;
                }
                // 设置公共字段
                costing.setProjectNo(projectNo);
                costing.setOperator(operator);

                // 处理折扣率（提前在Excel导入时处理更佳）
                // 将字符串转换为 double
                BigDecimal rate = StringUtils.isNotEmpty(costing.getDiscountRate()) ? new BigDecimal(costing.getDiscountRate()) : BigDecimal.ONE;
                try {

                    // 创建 DecimalFormat 实例，保留四位小数，并显示前导零
//                    DecimalFormat df = new DecimalFormat("0.0000"); // 四位小数，且始终显示整数部分
                    // 格式化
                    DecimalFormat df = new DecimalFormat("0.####");
                    String formattedRate = df.format(rate);

                    // 设置回 projectCosting 对象
                    costing.setDiscountRate(formattedRate);
                } catch (NumberFormatException e) {
                    costing.setDiscountRate("0");
                }

                //数量
                BigDecimal count = costing.getCount();

                //单价
                BigDecimal price = costing.getPrice();

                //总价 清单中的
                BigDecimal totalPrice = costing.getTotalPrice();

                if (price == null) {
                    throw new ServiceException("请填写设备“" + costing.getName() + "”的单价后重新上传");
                }
                //计算出的总价   数量乘以单价
                BigDecimal calculatedTotal = count.multiply(price);

                BigDecimal diff = calculatedTotal.subtract(totalPrice).abs();
                if (diff.compareTo(BigDecimal.ONE) > 0) { // 如果差值大于 1 元
                    throw new ServiceException("设备“" + costing.getName() + "”的数量为:" + count + ",单价为:" + price + " 总价应为:" + calculatedTotal + ",与实际清单中的总价:" + totalPrice + ",不符,差额为:" + diff + ",请正确填写后再上传");
                }
                //使用计算的总价乘以折扣率 判断是否等于折后价(误差允许在一块钱之内)
                if (StringUtils.isNotEmpty(costing.getDiscountRate()) && costing.getDiscountPrice() != null) {
                    //折扣价: 总价乘以折扣率
                    BigDecimal disTotal = calculatedTotal.multiply(rate);
                    // 计算差值的绝对值 如果没有折后价
                    BigDecimal discountPrice = Optional.ofNullable(costing.getDiscountPrice())
                            .orElse(BigDecimal.ONE);
                    BigDecimal diff1 = disTotal.subtract(discountPrice).abs();
                    // 判断是否超过允许的误差范围（1元）
                    if (diff1.compareTo(BigDecimal.ONE) > 0) {
                        throw new ServiceException("设备“" + costing.getName() + "”的总价为:" + calculatedTotal + ",折扣率为:" + rate + ",折后价应为:" + disTotal + "与实际清单中的折后总价:" + costing.getDiscountPrice() + " 不符,请正确填写后再上传");
                    }
                }
                if (StringUtils.isNotEmpty(costing.getRemarkCode())) {
                    //1.如果有备注编码的,使用备注编码查询对应的设备id
                    //2.判断设备id是否存在与管家婆项目中 不存在就标记
                    LambdaQueryWrapper<ProjectGoods> goodsWrapper = new QueryWrapper<ProjectGoods>().lambda();
                    goodsWrapper.eq(ProjectGoods::getModal, costing.getRemarkCode());
                    List<ProjectGoods> goodsList = projectGoodsService.list(goodsWrapper);
                    //3.备注编码不是唯一的 如果查询到多个 和出库单的对应一下
                    if (StringUtils.isNotEmpty(costing.getRemarkCode())) {
                        for (ProjectGoods goods : goodsList) {
                            String id = goods.getId();
                            LambdaQueryWrapper<ProjectSale> salesWrapper = new LambdaQueryWrapper<>();
                            salesWrapper.eq(ProjectSale::getGoodsId, id);
                            salesWrapper.eq(ProjectSale::getHousekeeperProject, housekeeperProject);
                            List<ProjectSale> saleListR = projectSaleService.list(salesWrapper);
                            for (ProjectSale sale : saleListR) {
                                String goodsId = sale.getGoodsId();
                                costing.setGoodsId(goodsId);
                                break;
                            }

                        }
                    }
                    if (goodsIds != null) {
                        if (!goodsIds.contains(costing.getGoodsId())) {
                            // 如果没有包含在出库单中 标记
                            costing.setStatus("1");
                        }
                    } else {
                        // 处理goodsIds为null的情况
                        System.out.println("The goodsIds collection is null.");
                        // 可能需要在这里根据业务逻辑设置costing的状态或其他操作
                        costing.setStatus("1"); // 假设当goodsIds为null时，默认标记状态为"1"
                    }


                    //使用备注编码没查询到 也标记
                    if (goodsList == null || goodsList.size() == 0) {
                        costing.setStatus("1");
                    }


                } else {
                    //没有直接标记
                    costing.setStatus("1");
                }
                validList.add(costing);
            }
        }
        BigDecimal totalDiscount = BigDecimal.ZERO;
        for (ProjectCosting costing : validList) {
            if (costing.getDiscountPrice() != null) {
                totalDiscount = totalDiscount.add(costing.getDiscountPrice());
            } else {
                totalDiscount = totalDiscount.add(costing.getTotalPrice());
            }
        }


        // 校验合同金额
        if (contractAmount != null && totalDiscount != null) {
            BigDecimal diff = contractAmount.subtract(totalDiscount).abs();
            if (diff.compareTo(BigDecimal.ONE) > 0) {
                if ("5".equals(type)) {
                    throw new RuntimeException(String.format(
                            "合同金额与清单统计金额不相等，请检查正式清单是否填写有误。清单统计金额为: %.2f，合同金额为: %.2f",
                            totalDiscount.stripTrailingZeros().doubleValue(),
                            contractAmount.stripTrailingZeros().doubleValue()
                    ));
                }
                if ("22".equals(type)) {
                    throw new RuntimeException(String.format("合同金额与清单统计金额不相等，请检查正式清单是否填写有误。清单统计金额为: %.2f，结算金额为: %.2f。",
                            totalDiscount.stripTrailingZeros().doubleValue(),
                            contractAmount.stripTrailingZeros().doubleValue()
                    ));
                }

            }
        } else {
            throw new RuntimeException("合同金额或清单金额为空");
        }

        // 批量插入数据
        if (!validList.isEmpty()) {
            try {
                // 删除旧数据
                if (isDelete) {
                    projectCostingMapper.deleteByProjectNo(projectNo);
                }
                projectCostingService.saveOrUpdateBatch(validList); // 需自定义批量插入方法
            } catch (Exception e) {
                throw new ServiceException("批量插入失败");
            }
        }


        return StringUtils.format("成功导入{}条数据", validList.size());
    }

    // 辅助方法：构建唯一键（处理空model）
    private String buildKey(String name, String model) {
        return name + "|" + (model == null ? "" : model);
    }

}
